﻿using Shop.Core.Enums;
using Shop.Core.Redis;
using Shop.Core.Repository;
using Shop.Model.Entity.Order;
using Shop.Model.Entity.Use;

namespace Shop.Tasks
{
    public class HangfireJobService
    {
        private readonly RepositoryBase<Orders> _orderRepository;
        private readonly RepositoryBase<UserWallet> _walletRepository;
        private readonly IRedisProvider _redisProvider;
        public HangfireJobService(RepositoryBase<Orders> orderRepository
            , RepositoryBase<UserWallet> walletRepository
            , IRedisProvider redisProvider)
        {
            _orderRepository = orderRepository;
            _walletRepository = walletRepository;
            _redisProvider = redisProvider;
        }

        /// <summary>
        /// 支付单超期检查
        /// </summary>
        public void PaymentOrderTimeoutCheck()
        {
            var endtime = DateTime.Now.AddHours(-1);
            _orderRepository.AsUpdateable()
                .Where(x => x.OrderStatus == (int)OrderStatus.Normal && x.CreateTime < endtime)
                .SetColumns(x => new Orders() { OrderStatus = (int)OrderStatus.Cancel})
                .ExecuteCommand();
        }

        /// <summary>
        /// 自动收货
        /// </summary>
        public async Task ReceiptCheck()
        {
            var order = _orderRepository.Where(x => x.OrderStatus == (int)OrderStatus.Ship && x.DeliveryTime < DateTime.Now.AddDays(-7))
                .ToList();
            foreach(var item in order)
            {
                await Settlement(item.Id);
                item.OrderStatus = (int)OrderStatus.Receipt;
                item.ReceiveTime = DateTime.Now;
                _orderRepository.Update(item);
            }
               
        }

        /// <summary>
        /// 结束
        /// </summary>
        /// <param name="orderId"></param>
        /// <returns></returns>
        private async Task Settlement(long orderId)
        {
            var data = await _walletRepository.Queryable<UserWalletLog>()
                .Where(x => x.SourceOrder == orderId && (x.Action == (int)WalletSourceTypes.Distribution || x.Action == (int)WalletSourceTypes.Prize) && x.State == 0)
                .ToListAsync();
            if (data.Count > 0)
            {
                foreach (var item in data)
                {
                    var cacheKey = "wallet:" + item.UserId;
                    var flag = await _redisProvider.LockAsync(cacheKey);
                    if (!flag.Success)
                    {
                        await Task.Delay(300);
                        flag = await _redisProvider.LockAsync(cacheKey);
                    }
                    try
                    {
                        var wallet = await _walletRepository.GetFirstAsync(x => x.UserId == item.UserId);
                        if (wallet == null || wallet.Surplus < item.Amount)
                            break;
                        wallet.Balance += item.Amount;
                        wallet.Surplus -= item.Amount;
                        await _walletRepository.UpdateAsync(wallet);
                        item.State = 1;
                        item.FinishTime = DateTime.Now;
                    }
                    finally
                    {
                        await _redisProvider.SafedUnLockAsync(cacheKey, flag.LockValue);
                    }
                }
                await _walletRepository.Change<UserWalletLog>().UpdateRangeAsync(data);
            }
        }
    }
}
